﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Concat
{
    class ClassType : ConcatType
    {
        public ClassType[] children;
        public StructType[] members;
        public Method[] protocol;

        public ClassType(string name, Method[] protocol)
            : base(name)
        {
            this.protocol = protocol;
            this.members = new StructType[0];
        }
        public ClassType(string name, ClassType/*[]*/ parent/*s*/, Method[] protocol)
            : this(name, protocol)
        {
            //foreach (ClassType parent in parents)
            //    parent.addChild(this);
            parent.addChild(this);

            this.protocol = protocol;
            this.members = new StructType[0];
        }

        public override bool coversNotEqual(ConcatType other)
        {
            if (other is ClassType)
            {
                return children.Contains(other)
                    || children.exists(child => child.covers((ClassType)other));
            }
            else
            {
                return members.Contains(other)
                    || members.exists(member => member.covers((StructType)other));
            }
        }

        public void addChild(ClassType child)
        {
            List<ClassType> list = new List<ClassType>(children);
            list.Add(child);
            children = list.ToArray();
        }
        public void addMember(StructType member)
        {
            List<StructType> list = new List<StructType>(members);
            list.Add(member);
            members = list.ToArray();
        }

        public bool followsProtocol(StructType member, MultiMethod[] multimethods)
        {
            // foreach method in the protocol,
            //   substitute the class name for the member name in the method
            //   if the multimethod list does not include the new method, then fail
            foreach (Method method in protocol)
            {
                Method specialized = method.substType(this, member);
                if (!multimethods
                    .exists(multi => multi//.substType(this, member)
                        .methods.exists(other => Method.sameTypes(other, specialized))))
                    return false;
            }
            return true;
        }
    }
}
